package org.coco.mybatis.xml;

import org.coco.mybatis.Configuration;
import org.coco.mybatis.mapping.MappedStatement;
import org.coco.mybatis.mapping.ResultMap;
import org.coco.mybatis.mapping.ResultMapping;
import org.coco.mybatis.sql.JavaType;
import org.coco.mybatis.sql.JdbcType;
import org.coco.mybatis.sql.SqlSource;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DocumentReader{


    private List<String> fileList;
    private SAXReader reader;
    private Document document;
    private Configuration configuration;
    private Map<String, MappedStatement> mappedStatementMap;

    public DocumentReader(List<String> fileList) {
        this.fileList = fileList;
        this.configuration = Configuration.getInstance();
        this.mappedStatementMap = configuration.getMappedStatementMap();
    }

    public void parseDocument() {
         this.doParseDocument(fileList);
    }

    private void doParseDocument(List<String> fileList) {
        if(fileList.size() > 0){
            for(String url : fileList) {
                try {
                    reader = new SAXReader();
                    document = reader.read(new File(url));
                    doParseElement(document);
                }catch (Exception e) {
                     throw new RuntimeException(e);
                }
            }
        }
    }


    private void doParseElement(Document documentRoot) {
        MappedStatement mappedStatement = new MappedStatement();
        Element rootElement = documentRoot.getRootElement();
        //获取mapper节点的namespace属性值
        String namespaceResult = rootElement.attributeValue("namespace");
        if(configuration.getMappedStatementMap().containsKey(namespaceResult)) {
            throw new RuntimeException("xml配置文件的namespace重复了");
        }
        //获取mapper的子节点
        List elements = rootElement.elements();
        List<SqlSource> sqlSourceList = new ArrayList<>();
        Map<String,ResultMap> resultMap = null;
        for(int i = 0; i < elements.size(); i ++) {
            Element childElement = (Element) elements.get(i);
            if("resultMap".equals(childElement.getName())) {
                //解析resultMap
                resultMap = parseResultMap(childElement,namespaceResult);
            }else if("select".equals(childElement.getName()) || "update".equals(childElement.getName()) ||
                    "delete".equals(childElement.getName()) || "insert".equals(childElement.getName())){
                //解析sql
                SqlSource sqlSource = parseSqlElement(childElement,namespaceResult,childElement.getName());
                sqlSourceList.add(sqlSource);
            }
            //todo 解析其它标签
        }
        mappedStatement.setResultMap(resultMap);
        mappedStatement.setSqlSourceList(sqlSourceList);
        configuration.getMappedStatementMap().put(namespaceResult,mappedStatement);
    }

    private SqlSource parseSqlElement(Element sqlElement, String namespaceResult, String sqlType) {
        SqlSource sqlSource = new SqlSource();
        String sql = sqlElement.getText();
        String id = namespaceResult + "." + sqlElement.attributeValue("id");
        String returnType = sqlElement.attributeValue("resultType");
        String returnMap = sqlElement.attributeValue("resultMap");
        String parameterType = sqlElement.attributeValue("parameterType");
        sqlSource.setSqlType(sqlType);
        sqlSource.setId(id);
        sqlSource.setReturnMap(returnMap);
        sqlSource.setReturnType(returnType);
        sqlSource.setSqlContent(sql);
        sqlSource.setParameterType(parameterType);
        return sqlSource;
    }

    private Map<String, ResultMap> parseResultMap(Element resultMapElement, String namespaceResult) {
        //获取ResultMap节点的id和type属性
        String id = resultMapElement.attributeValue("id");
        String type = resultMapElement.attributeValue("type");
        String mappedStatementMapKey = namespaceResult + id;
        if(mappedStatementMap.containsKey(mappedStatementMapKey)) {
            throw new RuntimeException("namespace 重复了");
        }
        //开始解析ResultMap的子节点
        List childElements = resultMapElement.elements();
        List<ResultMapping> resultMappingList = parseResultMapChildElement(childElements);
        resultMappingList.stream().forEach(resultMapping -> {
            resultMapping.setId(id);
        });
        ResultMap resultMap = new ResultMap();
        resultMap.setId(id);
        resultMap.setType(type);
        resultMap.setResultMappingList(resultMappingList);
        Map<String,ResultMap> resultMapMap = new HashMap<>();
        resultMapMap.put(id,resultMap);
        return resultMapMap;
    }

    private List<ResultMapping> parseResultMapChildElement(List childElements) {
        List<ResultMapping> resultMappingList = new ArrayList<>();
        ResultMapping resultMapping = null;
        for(int i = 0; i < childElements.size(); i ++) {
            Element elementChild = (Element) childElements.get(i);
            if("id".equals(elementChild.getName())) {
                String column = elementChild.attributeValue("column");
                String jdbcType = elementChild.attributeValue("jdbcType");
                String property = elementChild.attributeValue("property");
                String javaType = elementChild.attributeValue("javaType");
                resultMapping = new ResultMapping(column,jdbcType,property,javaType, JdbcType.parseByValue(jdbcType), JavaType.parseByValue(javaType));
                resultMappingList.add(resultMapping);
            }else if("result".equals(elementChild.getName())){
                String column = elementChild.attributeValue("column");
                String jdbcType = elementChild.attributeValue("jdbcType");
                String property = elementChild.attributeValue("property");
                String javaType = elementChild.attributeValue("javaType");
                resultMapping = new ResultMapping(column,jdbcType,property,javaType, JdbcType.parseByValue(jdbcType), JavaType.parseByValue(javaType));
                resultMappingList.add(resultMapping);
            }else {
               throw new RuntimeException(elementChild.getName() + " 是未知的标签");
            }
        }
        return resultMappingList;
    }



}
